package com.citywithincity.redis.utils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.citywithincity.db.interfaces.IValueConvert;
import com.citywithincity.redis.utils.impl.RedisFieldImpl;
import com.citywithincity.utils.ClassUtil;
import com.damai.utils.value.ValueConvertFactory;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

import redis.clients.jedis.Jedis;

/**
 * 快速的将object转为map，或者将map转为object
 * @author renxueliang
 *
 */
public class RedisSchema<T> {
	
	private Schema<T> schema;
	
	private  RedisField[] fields;
	
	private String[] keys;
	
	private static Map<Class<?>, RedisSchema<?>> map = new HashMap<Class<?>, RedisSchema<?>>();
	
	@SuppressWarnings("unchecked")
	public static <T> RedisSchema<T> get(Class<T> clazz) {
		RedisSchema<T> schema = (RedisSchema<T>) map.get(clazz);
		synchronized (map) {
			schema = (RedisSchema<T>) map.get(clazz);
			if(schema==null){
				schema = new RedisSchema<T>(clazz);
				map.put(clazz, schema);
			}
		}
		return schema;
	}
	
	RedisSchema(Class<T> clazz){
		schema = RuntimeSchema.getSchema(clazz);
		try {
			fields = bind(clazz);
			keys = new String[fields.length];
			int index=0;
			for (RedisField redisField : fields) {
				keys[index++] = redisField.getName();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	private static <T> RedisField[] bind(Class<T> clazz) throws Exception {
		Field[] fields = ClassUtil.getFields(clazz);
		RedisField[]  result = new RedisField[fields.length];
		int index = 0;
		for (Field field : fields) {
			IValueConvert toStringConvert = null;
			IValueConvert toValueConvert = null;
			field.setAccessible(true);
			
			if(field.getType() != String.class){
				toStringConvert = ValueConvertFactory.create(field.getType(), String.class);
				toValueConvert = ValueConvertFactory.create(String.class, field.getType());
			}
			
			
			result[index++]=new RedisFieldImpl(field, toStringConvert, toValueConvert);
			//Data2EntityCreator.createSimple(fromClass, toClass)
		}
		return result;
	}

	
	
	
	public T fromMap(Map<String, String> map){
		T data = schema.newMessage();
		for (RedisField redisField : fields) {
			redisField.set(data, map.get(redisField.getName()));	
		}
		return data;
	}
	
	public Map<String, String> toMap(T data){
		Map<String, String> result = new HashMap<String, String>(fields.length);
		for (RedisField redisField : fields) {
			String value =  redisField.get(data);
			if(value==null)continue;
			result.put(redisField.getName(),value);
		}
		return result;
	}
	
	
	public String getValue(Jedis jedis,String key,Object id,String field){
		return jedis.hget(RedisUtil.getKey(key, id), field);
	}
	
	public T hget(Jedis jedis,String key, Object id) {
		T data = schema.newMessage();
		List<String> list = jedis.hmget(RedisUtil.getKey(key, id), keys);
		int index = 0;
		for (RedisField field : fields) {
			String value = list.get(index++);
			field.set(data, value);
		}
		return data;
	}


	
}
